<!DOCTYPE html>
<html lang="en">
<head>
  <title>egg - Born to build better enterprise frameworks and apps</title>
  <meta charset="utf-8">
  <meta name="description" content="index.description">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/images/favicon.png" type="image/x-icon">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
<link rel="stylesheet" href="/css/index.css">

    <script>
    !function(t,e,a,r,c){t.TracertCmdCache=t.TracertCmdCache||[],t[c]=window[c]||
      {_isInit:!0,call:function(){t.TracertCmdCache.push(arguments)},
      start:function(t){this.call('start',t)}},t[c].l=new Date;
      var n=e.createElement(a),s=e.getElementsByTagName(a)[0];
      n.async=!0,n.src=r,s.parentNode.insertBefore(n,s)}
    (window,document,'script','https://tracert.alipay.com/tracert.js','Tracert');
      Tracert.start({
        plugins: [ 'BucName' ],
        spmAPos: 'a454',
        spmBPos: 'b4893',
      });
    </script>
  
</head>
<body>
  <div class="nav" >
  <header>
    <a href="/en/" class="nav-logo leftpadding" alt="egg"><img src="https://zos.alipayobjects.com/rmsportal/VTcUYAaoKqXyHJbLAPyF.svg"></a>
    <ul class="nav-item">
      <li>
        <form id="search-form">
          <input type="text" id="search-query" class="search-query st-default-search-input">
        </form>
      </li>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/basics/plugin.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/basics/plugin.html" >中文</a></li></ul>
        </li>
      
      <li><iframe src="https://ghbtns.com/github-btn.html?user=eggjs&repo=egg&type=star&count=true" frameborder="0" scrolling="0" width="150px" height="20px"></iframe></li>
    </ul>
    <a id="mobileTrigger" href="#" class="mobile-trigger">
      <ul>
        <li></li>
        <li></li>
        <li></li>
      </ul>
    </a>
  </header>
</div>
  <div id="container" class="container">
    <div class="page-main">
  <article class="markdown-body">
    <h1></h1>
    <h2 id="title-plugin"><a class="markdown-anchor" href="#title-plugin">#</a> title: Plugin</h2>
<p>Plugin mechanism is a major feature of our framework. Not only can it ensure that the core of the framework is sufficiently streamlined, stable and efficient, but also can promote the reuse of business logic and the formation of an ecosystem. In the following sections, we will try to answer questions such as</p>
<ul>
<li>Koa already has a middleware mechanism, why plugins?</li>
<li>What are the differences/relationship between middleware and plugins?</li>
<li>How do I use a plugin?</li>
<li>How do I write a plugin?</li>
<li>...</li>
</ul>
<h2 id="why-plugins"><a class="markdown-anchor" href="#why-plugins">#</a> Why plugins?</h2>
<p>Here are some of the issues we think that can arise when using Koa middleware:</p>
<ol>
<li>Middleware loading is sequential and it is the user's responsibility to setup the execution sequence since middleware mechanism can not manage the actual order. This, in fact, is not very friendly.
When the order is not correct, it can lead to unexpected results.</li>
<li>Middleware positioning is geared towards intercepting user requests to add additional logic before or after such as: authentication, security checks, logging and so on. However, in some cases, such functionality can be unrelated to the request, for example, timing tasks, message subscriptions, back-end logic and so on.</li>
<li>Some features include very complex initialization logic that needs to be done at application startup. This is obviously not suitable for middleware to achieve.</li>
</ol>
<p>To sum up, we need a more powerful mechanism to manage, orchestrate those relatively independent business logic.</p>
<h3 id="the-relationship-between-middleware-plugins-and-application"><a class="markdown-anchor" href="#the-relationship-between-middleware-plugins-and-application">#</a> The relationship between middleware, plugins and application</h3>
<p>A plugin is actually a &quot;mini-application&quot;, almost the same as an app:</p>
<ul>
<li>It contains <a href="./service.html">Services</a>, [middleware] (./ middleware.md), <a href="./config.html">config</a>, [framework extensions] (./ extend.md), etc.</li>
<li>It does not have separate [Router] (./ router.md) and <a href="./controller.html">Controller</a>.</li>
</ul>
<p>Their relationship is:</p>
<ul>
<li>Applications can be directly introduced into Koa's middleware.</li>
<li>When it comes to the scene mentioned in the previous section, the app needs to import the plugin.</li>
<li>The plugin itself can contain middleware.</li>
<li>Multiple plugins can be wrapped as an [upper frame] (../ advanced / framework.md).</li>
</ul>
<h2 id="using-plugins"><a class="markdown-anchor" href="#using-plugins">#</a> Using plugins</h2>
<p>Plugins are usually added via the npm module:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ npm i egg-mysql --save</span><br></pre></td></tr></table></figure>
<p>** Note: We recommend introducing dependencies in the <code>^</code> way, and locking versions are strongly discouraged. **</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"dependencies"</span>: &#123;</span><br><span class="line">    <span class="attr">"egg-mysql"</span>: <span class="string">"^ 3.0.0"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Then you need to declare it in the <code>config / plugin.js</code> application or framework:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// config / plugin.js</span></span><br><span class="line"><span class="comment">// Use mysql plug-in</span></span><br><span class="line">exports.mysql = &#123;</span><br><span class="line">  enable: <span class="literal">true</span>,</span><br><span class="line">  package: <span class="string">'egg-mysql'</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>You can directly use the functionality provided by the plugin:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">app.mysql.query(sql, values);</span><br></pre></td></tr></table></figure>
<h3 id="configuring-plugins"><a class="markdown-anchor" href="#configuring-plugins">#</a> Configuring plugins</h3>
<p>Each configuration item in <code>plugin.js</code> supports:</p>
<ul>
<li><code>{Boolean} enable</code> - Whether to enable this plugin, the default is true</li>
<li><code>{String} package</code> -<code>npm</code> module name, plugin is imported via <code>npm</code> module</li>
<li><code>{String} path</code> - The plugin's absolute path, mutually exclusive with package configuration</li>
<li><code>{Array} env</code> - Only enable plugin in the specified runtime (environment), overriding the plugin's own configuration in <code>package.json</code></li>
</ul>
<h3 id="enablingdisabling-plugins"><a class="markdown-anchor" href="#enablingdisabling-plugins">#</a> Enabling/Disabling plugins</h3>
<p>The application does not need the package or path configuration when using the plugins built in the upper framework. You only need to specify whether they are enabled or not:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// For the built-in plugin, you can use the following simple way to turn on or off</span></span><br><span class="line">exports.onerror = <span class="literal">false</span>;</span><br></pre></td></tr></table></figure>
<h3 id="environment-configuration"><a class="markdown-anchor" href="#environment-configuration">#</a> Environment configuration</h3>
<p>We also support <code>plugin.{Env}.js</code>, which will load plugin configurations based on <a href="../basics/env.html">Runtime</a>.</p>
<p>For example, if you want to load the plugin <code>egg-dev</code> only in the local environment, you can install it to <code>devDependencies</code> and adjust the plugin configuration accordingly.</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// npm i egg-dev --save-dev</span></span><br><span class="line"><span class="comment">// package.json</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">"devDependencies"</span>: &#123;</span><br><span class="line">    <span class="string">"egg-dev"</span>: <span class="string">"*"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Then declare in <code>plugin.local.js</code>:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// config / plugin.local.js</span></span><br><span class="line">exports.dev = &#123;</span><br><span class="line">  enable: <span class="literal">true</span>,</span><br><span class="line">  package: <span class="string">'egg-dev'</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>In this way, <code>npm i --production</code> in the production environment does not need to download the<code>egg-dev</code> package.</p>
<p>** Note: **</p>
<ul>
<li>
<p><code>plugin.default.js</code> does not exists. Use <code>local</code> for dev environments.</p>
</li>
<li>
<p>Use this feature only in the application layer. Do not use it in the framework layer.</p>
</li>
</ul>
<h3 id="package-name-and-path"><a class="markdown-anchor" href="#package-name-and-path">#</a> Package name and path</h3>
<ul>
<li>The <code>package</code> is introduced in the <code>npm</code> style which is the most common way to import</li>
<li><code>path</code> is an absolute path introduced when you want to load the plugin from different location such as when a plugin is still at the development stage or not available on <code>npm</code></li>
<li>To see the application of these two scenarios, please see [progressive development] (../ tutorials / progressive.md).</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// config / plugin.js</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span> (<span class="string">'path'</span>);</span><br><span class="line">exports.mysql = &#123;</span><br><span class="line">  enable: <span class="literal">true</span>,</span><br><span class="line">  package: path.join (__ dirname, <span class="string">'../lib/plugin/egg-mysql'</span>),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h2 id="plugin-configuration"><a class="markdown-anchor" href="#plugin-configuration">#</a> Plugin configuration</h2>
<p>The plugin will usually contain its own default configuration, you can overwrite this in <code>config.default.js</code>:</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// config / config.default.js</span></span><br><span class="line">exports.mysql = &#123;</span><br><span class="line">  client: &#123;</span><br><span class="line">    host: <span class="string">'mysql.com'</span>,</span><br><span class="line">    port: <span class="string">'3306'</span>,</span><br><span class="line">    user: <span class="string">'test_user'</span>,</span><br><span class="line">    password: <span class="string">'test_password'</span>,</span><br><span class="line">    database: <span class="string">'test'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>Specific consolidation rules can be found in [Configuration] (. / Config.md).</p>
<h2 id="plugin-list"><a class="markdown-anchor" href="#plugin-list">#</a> Plugin list</h2>
<ul>
<li>Framework has default built-in plugins for enterprise applications <a href="https://eggjs.org/zh-cn/plugins/">Common plugins</a>:
  - <a href="https://github.com/eggjs/egg-onerror" target="_blank" rel="noopener">onerror</a> Uniform Exception Handling
  - <a href="https://github.com/eggjs/egg-session" target="_blank" rel="noopener">Session</a> Session implementation
  - <a href="https://github.com/eggjs/egg-i18n" target="_blank" rel="noopener">i18n</a> Multilingual
  - <a href="https://github.com/eggjs/egg-watcher" target="_blank" rel="noopener">watcher</a> File and folder monitoring
  - <a href="https://github.com/eggjs/egg-multipart" target="_blank" rel="noopener">multipart</a> File Streaming Upload
  - <a href="https://github.com/eggjs/egg-security" target="_blank" rel="noopener">security</a> Security
  - <a href="https://github.com/eggjs/egg-development" target="_blank" rel="noopener">development</a> Development Environment Configuration
  - <a href="https://github.com/eggjs/egg-logrotator" target="_blank" rel="noopener">logrotator</a> Log segmentation
  - <a href="https://github.com/eggjs/egg-schedule" target="_blank" rel="noopener">schedule</a> Timing tasks
  - <a href="https://github.com/eggjs/egg-static" target="_blank" rel="noopener">static</a> Static server
  - <a href="https://github.com/eggjs/egg-jsonp" target="_blank" rel="noopener">jsonp</a> jsonp support
  - <a href="https://github.com/eggjs/egg-view" target="_blank" rel="noopener">view</a> Template Engine</li>
<li>More community plugins can be found on GitHub <a href="https://github.com/topics/egg-plugin" target="_blank" rel="noopener">egg-plugin</a>.</li>
</ul>
<h2 id="developing-a-plugin"><a class="markdown-anchor" href="#developing-a-plugin">#</a> Developing a plugin</h2>
<p>See the documentation <a href="../advanced/plugin.html">plugin development</a>.</p>

  </article>
  <aside id="mobileAside" class="toc">
  <div class="mobile-menu">
    <ul>
      <li><a href="/en/intro/" alt="Guide">Guide</a></li><li><a href="/api/" alt="API">API</a></li><li><a href="/en/tutorials/index.html" alt="Tutorials">Tutorials</a></li><li><a href="https://github.com/search?q=topic%3Aegg-plugin&type=Repositories" alt="Plugins">Plugins</a></li><li><a href="https://github.com/eggjs/egg/releases" alt="Release">Release</a></li>
      
      
        <li class="translations">
          <a class="nav-link">中文文档</a>
          <span class="arrow"></span><ul id="dropdownContent" class="dropdown-content"><li><a id="en" href="/en/basics/plugin.html" style="color: #22ab28">English</a></li><li><a id="zh-cn" href="/zh-cn/basics/plugin.html" >中文</a></li></ul>
        </li>
      
    </ul>
  </div>
  <dl><dt id="title-Intro" style="cursor: pointer;" class="aside-title">Guide<a id="collapse-icon-Intro" class="icon opend"></a></dt><dd id=panel-Intro><ul><li><a href="/en/intro/index.html" class="menu-link">What is Egg?</a></li><li><a href="/en/intro/egg-and-koa.html" class="menu-link">Egg and Koa</a></li><li><a href="/en/intro/quickstart.html" class="menu-link">Quick Start</a></li><li><a href="/en/tutorials/progressive.html" class="menu-link">Progressive</a></li><li><a href="/en/migration.html" class="menu-link">Migration to 2.x</a></li></ul></dd><dt id="title-Basics" style="cursor: pointer;" class="aside-title">Basis Function<a id="collapse-icon-Basics" class="icon opend"></a></dt><dd id=panel-Basics><ul><li><a href="/en/basics/structure.html" class="menu-link">Directory Structure</a></li><li><a href="/en/basics/objects.html" class="menu-link">Built-in Objects</a></li><li><a href="/en/basics/env.html" class="menu-link">Environment</a></li><li><a href="/en/basics/config.html" class="menu-link">Configuration</a></li><li><a href="/en/basics/middleware.html" class="menu-link">Middleware</a></li><li><a href="/en/basics/router.html" class="menu-link">Router</a></li><li><a href="/en/basics/controller.html" class="menu-link">Controller</a></li><li><a href="/en/basics/service.html" class="menu-link">Service</a></li><li><a href="/en/basics/plugin.html" class="menu-link">Plugin</a></li><li><a href="/en/basics/schedule.html" class="menu-link">Schedule</a></li><li><a href="/en/basics/extend.html" class="menu-link">Extend</a></li><li><a href="/en/basics/app-start.html" class="menu-link">Custom Init</a></li></ul></dd><dt id="title-Core" style="cursor: pointer;" class="aside-title">Core<a id="collapse-icon-Core" class="icon opend"></a></dt><dd id=panel-Core><ul><li><a href="/en/core/development.html" class="menu-link">Development</a></li><li><a href="/en/core/unittest.html" class="menu-link">Unit Testing</a></li><li><a href="/en/core/deployment.html" class="menu-link">Deployment</a></li><li><a href="/en/core/logger.html" class="menu-link">Logger</a></li><li><a href="/en/core/httpclient.html" class="menu-link">HttpClient</a></li><li><a href="/en/core/cookie-and-session.html" class="menu-link">Cookie and Session</a></li><li><a href="/en/core/cluster-and-ipc.html" class="menu-link">Cluster and IPC</a></li><li><a href="/en/core/view.html" class="menu-link">View</a></li><li><a href="/en/core/error-handling.html" class="menu-link">Error Handling</a></li><li><a href="/en/core/security.html" class="menu-link">Security</a></li><li><a href="/en/core/i18n.html" class="menu-link">i18n</a></li></ul></dd><dt id="title-Tutorials" style="cursor: pointer;" class="aside-title">Tutorials<a id="collapse-icon-Tutorials" class="icon opend"></a></dt><dd id=panel-Tutorials><ul><li><a href="/en/tutorials/mysql.html" class="menu-link">MySQL</a></li><li><a href="/en/tutorials/restful.html" class="menu-link">RESTful API</a></li><li><a href="/en/tutorials/passport.html" class="menu-link">Passport</a></li><li><a href="/en/tutorials/socketio.html" class="menu-link">Socket.IO</a></li><li><a href="/en/tutorials/assets.html" class="menu-link">Assets</a></li><li><a href="/en/tutorials/typescript.html" class="menu-link">TypeScript</a></li></ul></dd><dt id="title-Advanced" style="cursor: pointer;" class="aside-title">Advanced<a id="collapse-icon-Advanced" class="icon opend"></a></dt><dd id=panel-Advanced><ul><li><a href="/en/advanced/loader.html" class="menu-link">Loader</a></li><li><a href="/en/advanced/plugin.html" class="menu-link">Plugin Development</a></li><li><a href="/en/advanced/framework.html" class="menu-link">Framework</a></li><li><a href="/en/advanced/cluster-client.html" class="menu-link">Cluster Enhancement</a></li><li><a href="/en/advanced/view-plugin.html" class="menu-link">View Plugin</a></li><li><a href="/en/style-guide.html" class="menu-link">Style Guide</a></li></ul></dd><dt id="title-Community" style="cursor: pointer;" class="aside-title">Community<a id="collapse-icon-Community" class="icon opend"></a></dt><dd id=panel-Community><ul><li><a href="/en/plugins/" class="menu-link">Plugin List</a></li><li><a href="/en/contributing.html" class="menu-link">Contributing</a></li><li><a href="/en/resource.html" class="menu-link">Resource</a></li><li><a href="/en/faq.html" class="menu-link">FAQ</a></li></ul></dd></dl>
</aside>
<script>
var mobileTrigger = document.getElementById('mobileTrigger');
var mobileAside = document.getElementById('mobileAside');

var expandMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon opend';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = '';
  }
}

var collapseMenu = function(title) {
  // handle icon
  const collapseIcon = document.getElementById('collapse-icon-' + title);
  if (collapseIcon) {
    collapseIcon.className = 'icon closed';
  }
  // handle panelEle
  const panelEle = document.getElementById('panel-' + title);
  if (panelEle) {
    panelEle.className = 'aside-panel-hidden';
  }
}

mobileAside.onclick = function(e) {
  const targetId = e.target.id;
  if (targetId && (targetId.indexOf('title-') > -1 || targetId.indexOf('collapse-icon-') > -1)) {
    const title = targetId.replace('title-', '').replace('collapse-icon-', '');
    try { 
      // the the browser may have no localStroage or JSON.parse may throw exception.
      const menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
        
      // current menu status
      const curClosed = menuInfo[title] ? menuInfo[title].closed : false; // default false

      // change UI
      curClosed ? expandMenu(title) : collapseMenu(title);

      // save menuInfo to localStorage
      menuInfo[title] = { closed: !curClosed } // opposite
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    } catch (e) {}
  }
};

mobileTrigger.onclick = function(e) {
  e.preventDefault();
  if (mobileAside.className.indexOf('mobile-show') === -1) {
    mobileAside.className += ' mobile-show';
  } else {
    mobileAside.className = 'toc';
  }
};

(function() {
  // save data to localStorage because the page will refresh when user change the url.
  let menuInfo;
  try { 
    // the the browser may have no localStroage or JSON.parse may throw exception.
    menuInfo = JSON.parse(window.localStorage.getItem('menuInfo'));
    if (!menuInfo) {
      menuInfo = {};
      window.localStorage.setItem('menuInfo', JSON.stringify(menuInfo));
    }
  } catch (e) {
    menuInfo = {}; // default {}
  }

  for (const title in menuInfo) {
    if (menuInfo[title] && menuInfo[title].closed) { // menu in closed status.
      collapseMenu(title);
    } else {
      expandMenu(title);
    }
  }

  // highlight menu
  const pathname = window.location.pathname;
  const selector = `a[href="${pathname}"].menu-link,a[href="${pathname}index.html"].menu-link`;
  const menuItem = mobileAside.querySelector(selector);
  if (menuItem) { menuItem.className += ' highlight'; }
})();
</script>

</div>

  </div>
</body>
<script src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
<script>
docsearch({
  apiKey: '1561de31a86f79507ea00cdb54ce647c',
  indexName: 'eggjs',
  inputSelector: '#search-query',
});
</script>
<div class="cnzz">
<script src="https://s11.cnzz.com/z_stat.php?id=1261142226&web_id=1261142226" language="JavaScript"></script>
</div>

</html>
